package com.beyond.core.service;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.beyond.core.handler.NettyServerHandler;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
/**
 * 通讯服务器端入口主程序
 * @author wyd
 * @date 2020年9月21日-下午2:30:30
 */
@Component
@Slf4j
public class CommuniationService {
	
	@Value("${server.port}")
	Integer port;  //接收监听端口
//	@Value("${remote.port}")
//	Integer sendPort; //发送端口
	
	 private static ExecutorService ex = new ThreadPoolExecutor(10, Integer.MAX_VALUE,
	            2L, TimeUnit.SECONDS,
	            new LinkedBlockingQueue<Runnable>());
	
	public  static ChannelGroup allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
	private final EventLoopGroup boss = new NioEventLoopGroup();
	ChannelFuture f = null;
   
	public ChannelFuture startService() {	
		
		try {
			//通过NioDatagramChannel创建Channel，并设置Socket参数支持广播
            //UDP相对于TCP不需要在客户端和服务端建立实际的连接，因此不需要为连接（ChannelPipeline）设置handler

			Bootstrap bootstrap = new Bootstrap();
			bootstrap.group(boss);
			bootstrap.channel(NioDatagramChannel.class);
			bootstrap.option(ChannelOption.SO_BROADCAST, true) // 设置广播
					 .option(ChannelOption.SO_RCVBUF, 1024 * 1024 * 2)// 设置UDP读缓冲区为2M
					 .option(ChannelOption.SO_SNDBUF, 1024 * 1024)// 设置UDP写缓冲区为1M
			         .handler(new NettyServerHandler(ex));
			
			 f = bootstrap.bind(port).sync();
			if (f.isSuccess()) {
				log.info("UDP服务器启动成功！端口号：" + port);
			}
			// 在端口绑定之后，给channel增加一个管道关闭的监听器并同步阻塞，直到管道关闭，线程才会往下执行，结束进程
			f.channel().closeFuture().sync();
		 } catch (Exception e) {
				log.error("通讯服务器启动异常，异常信息：{}", e);
				e.printStackTrace();
				boss.shutdownGracefully();
			}
		return f;	
		
	}
	
	public void destroyService() {
		
		 log.info("通讯服务器关闭...");
		 allChannels.close().awaitUninterruptibly();
		 boss.shutdownGracefully();
	     log.info("通讯服务器关闭成功!");
	}
   
}
